本文共 13392 字,大约阅读时间需要 44 分钟。
检测是否支持workman
[root@iZbp1esy3n96esf69makhbZ ~]# curl -Ss http://www.workerman.net/check.php | phpPHP Version >= 5.3.3 [OK] Extension pcntl check [fail] Extension posix check [OK]
源码编译安装(一般是安装PHP自带的扩展,以安装pcntl扩展为例)
1、利用php -v
命令查看当前的PHP CLI的版本
~# php -vPHP 5.3.29-1~dotdeb.0 with Suhosin-Patch (cli) (built: Aug 14 2014 19:55:20)Copyright (c) 1997-2014 The PHP GroupZend Engine v2.3.0, Copyright (c) 1998-2014 Zend Technologies
2、根据版本下载PHP源代码
PHP历史版本下载页面:
3、解压源码压缩包
例如下载的压缩包名称是php-5.3.29.tar.gz
~# tar -zxvf php-5.3.29.tar.gzphp-5.3.29/php-5.3.29/README.WIN32-BUILD-SYSTEMphp-5.3.29/netware/...
4、进入源码中的ext/pcntl目录
~# cd php-5.3.29/ext/pcntl/
5、运行 phpize
命令
~# phpizeConfiguring for:PHP Api Version: 20090626Zend Module Api No: 20090626Zend Extension Api No: 220090626
6、运行 configure
命令
~# ./configurechecking for grep that handles long lines and -e... /bin/grepchecking for egrep... /bin/grep -E...
7、运行 make
命令
~# make/bin/bash /tmp/php-5.3.29/ext/pcntl/libtool --mode=compile cc ...-I/usr/include/php5 -I/usr/include/php5/main -I/usr/include/php5/TSRM -I/usr/include/php5/Zend......
8、运 行make install
命令
~# make installInstalling shared extensions: /usr/lib/php5/20090626/
9、配置ini文件
通过运行 php --ini
查找php.ini文件位置,然后在文件中添加extension=pcntl.so
说明: 此方法一般用来安装PHP自带的扩展,例如posix扩展和pcntl扩展。除了用phpize编译某个扩展,也可以重新编译整个PHP,在编译时用参数添加扩展,例如在源码根目录运行
~# ./configure --enable-pcntl --enable-posix ...~# make && make install
再次检测是否支持workman
[root@iZbp1esy3n96esf69makhbZ ~]# curl -Ss http://www.workerman.net/check.php | phpPHP Version >= 5.3.3 [OK] Extension pcntl check [OK] Extension posix check [OK]
下面弄服务端:
参考:
我是直接用Workerman开启SSL,
array( // 请使用绝对路径 'local_cert' => '磁盘路径/server.pem', // 也可以是crt文件 'local_pk' => '磁盘路径/server.key', 'verify_peer' => false, // 'allow_self_signed' => true, //如果是自签名证书需要开启此选项 ));// 这里设置的是websocket协议(端口任意,但是需要保证没被其它程序占用)$worker = new Worker('websocket://0.0.0.0:8282', $context);// 设置transport开启ssl,websocket+ssl即wss$worker->transport = 'ssl';$worker->onMessage = function($con, $msg) { $con->send('ok');};Worker::runAll();
注意:
1.如果无法启动,则一般是443端口被占用,请改成其它端口,注意改成其它端口后客户端连接时需要带上端口号,客户端连接时地址类似wss://domain.com:xxx ,xxx为端口号
2.证书一般是与域名绑定的,所以测试的时候客户端请使用域名连接,不要使用ip去连
接着小程序端:
参考:
一、服务器域名配置
微信小程序后台配置wss:域名:端口
二、客户端
2、小程序端的代码
Uitls/websocket.js:
var url = 'wss://www.xxx.cn';//服务器地址 function connect(user, func) { wx.connectSocket({ url: url, header: { 'content-type': 'application/json' }, success: function () { console.log('websocket连接成功~') }, fail: function () { console.log('websocket连接失败~') } }) wx.onSocketOpen(function (res) { wx.showToast({ title: 'websocket已开通~', icon: "success", duration: 2000 }) //接受服务器消息 wx.onSocketMessage(func);//func回调可以拿到服务器返回的数据 }); wx.onSocketError(function (res) { wx.showToast({ title: 'websocket连接失败,请检查!', icon: "none", duration: 2000 }) })} //发送消息function send(msg) { wx.sendSocketMessage({ data: msg });} module.exports = { connect: connect, send: send}JS:
// pages/socks/socks.js
const app = getApp()var websocket = require('../../utils/websocket.js');var utils = require('../../utils/util.js'); Page({ /** * 页面的初始数据 */ data: { newslist: [], userInfo: {}, scrollTop: 0, increase: false,//图片添加区域隐藏 aniStyle: true,//动画效果 message: "", previewImgList: [] }, /** * 生命周期函数--监听页面加载 */ onLoad: function () { var that = this if (app.globalData.userInfo) { this.setData({ userInfo: app.globalData.userInfo }) } //调通接口 websocket.connect(this.data.userInfo, function (res) { // console.log(JSON.parse(res.data)) var list = [] list = that.data.newslist list.push(JSON.parse(res.data)) that.setData({ newslist: list }) }) }, // 页面卸载 onUnload() { wx.closeSocket(); wx.showToast({ title: '连接已断开~', icon: "none", duration: 2000 }) }, //事件处理函数 send: function () { var flag = this if (this.data.message.trim() == "") { wx.showToast({ title: '消息不能为空哦~', icon: "none", duration: 2000 }) } else { setTimeout(function () { flag.setData({ increase: false }) }, 500) websocket.send('{ "content": "' + this.data.message + '", "date": "' + utils.formatTime(new Date()) + '","type":"text", "nickName": "' + this.data.userInfo.nickName + '", "avatarUrl": "' + this.data.userInfo.avatarUrl + '" }') this.bottom() } }, //监听input值的改变 bindChange(res) { this.setData({ message: res.detail.value }) }, cleanInput() { //button会自动清空,所以不能再次清空而是应该给他设置目前的input值 this.setData({ message: this.data.message }) }, increase() { this.setData({ increase: true, aniStyle: true }) }, //点击空白隐藏message下选框 outbtn() { this.setData({ increase: false, aniStyle: true }) }, //发送图片 chooseImage() { var that = this wx.chooseImage({ count: 1, // 默认9 sizeType: ['original', 'compressed'], // 可以指定是原图还是压缩图,默认二者都有 sourceType: ['album', 'camera'], // 可以指定来源是相册还是相机,默认二者都有 success: function (res) { // 返回选定照片的本地文件路径列表,tempFilePath可以作为img标签的src属性显示图片 var tempFilePaths = res.tempFilePaths // console.log(tempFilePaths) wx.uploadFile({ url: 'wss://www.xxx.cn', //服务器地址 filePath: tempFilePaths[0], name: 'file', headers: { 'Content-Type': 'form-data' }, success: function (res) { if (res.data) { that.setData({ increase: false }) websocket.send('{"images":"' + res.data + '","date":"' + utils.formatTime(new Date()) + '","type":"image","nickName":"' + that.data.userInfo.nickName + '","avatarUrl":"' + that.data.userInfo.avatarUrl + '"}') that.bottom() } } }) } }) }, //图片预览 previewImg(e) { var that = this //必须给对应的wxml的image标签设置data-set=“图片路径”,否则接收不到 var res = e.target.dataset.src var list = this.data.previewImgList //页面的图片集合数组 //判断res在数组中是否存在,不存在则push到数组中, -1表示res不存在 if (list.indexOf(res) == -1) { this.data.previewImgList.push(res) } wx.previewImage({ current: res, // 当前显示图片的http链接 urls: that.data.previewImgList // 需要预览的图片http链接列表 }) }, //聊天消息始终显示最底端 bottom: function () { var query = wx.createSelectorQuery() query.select('#flag').boundingClientRect() query.selectViewport().scrollOffset() query.exec(function (res) { wx.pageScrollTo({ scrollTop: res[0].bottom // #the-id节点的下边界坐标 }) res[1].scrollTop // 显示区域的竖直滚动位置 }) },})WXML:
WXSS:系统消息: 欢迎 { { userInfo.nickName }} 加入聊天室 { {item.date}} { { item.nickName }} { {item.content}} { { item.nickName }} { {item.content}}
/* pages/socks/socks.wxss */ page { background-color: #f7f7f7; height: 100%; } /* 聊天内容 */ .news { padding-top: 30rpx; text-align: center; /* height:100%; */ box-sizing:border-box; } #flag{ margin-bottom: 100rpx; height: 30rpx; } .chat-notice{ text-align: center; font-size: 30rpx; padding: 10rpx 0; color: #666; } .historycon { height: 100%; width: 100%; /* flex-direction: column; */ display: flex; border-top: 0px; } /* 聊天 */ .chat-news{ width: 100%; overflow: hidden; } .chat-news .my_right { float: right; /* right: 40rpx; */ padding: 10rpx 10rpx; } .chat-news .name{ margin-right: 10rpx; } .chat-news .you_left { float: left; /* left: 5rpx; */ padding: 10rpx 10rpx; } .selectImg{ display: inline-block; width: 150rpx; height: 150rpx; margin-left: 50rpx; } .my_right .selectImg{ margin-right: 80rpx; } .new_img { width: 60rpx; height: 60rpx; border-radius: 50%; vertical-align: middle; margin-right: 10rpx; } .new_txt { max-width: 300rpx; display: inline-block; border-radius: 6rpx; line-height: 60rpx; background-color: #95d4ff; padding: 5rpx 20rpx; margin: 0 10rpx; margin-left: 50rpx; } .my_right .new_txt{ margin-right:60rpx; } .you{ background-color: lightgreen; } .my { border-color: transparent transparent transparent #95d4ff; } .you { border-color: transparent #95d4ff transparent transparent; } .hei{ margin-top: 50px; height: 20rpx; } .history { height: 100%; margin-top: 15px; padding: 10rpx; font-size: 14px; line-height: 40px; word-break: break-all; } ::-webkit-scrollbar { width: 0; height: 0; color: transparent; z-index: -1; } /* 信息输入区域 */ .message{ position: fixed; bottom:0; width: 100%; } .sendMessage{ display: block; height: 80rpx; padding: 10rpx 10rpx; background-color: #fff; border-top: 2rpx solid #eee; border-bottom: 2rpx solid #eee; z-index:3; } .sendMessage input{ float:left; width: 66%; height: 100%; line-height: 80rpx; border-bottom: 1rpx solid #ccc; padding:0 10rpx; font-size: 35rpx; color: #666; } .sendMessage view{ display: inline-block; width: 80rpx; height: 80rpx; line-height: 80rpx; font-size: 60rpx; text-align: center; color: #999; border: 1rpx solid #ccc; border-radius: 50%; margin-left: 10rpx; } .sendMessage button { float: right; font-size: 35rpx; } .increased{ width:100%; /* height: 150rpx; */ padding: 40rpx 30rpx; background-color: #fff; } .increased .image{ width: 100rpx; height: 100rpx; border: 3rpx solid #ccc; line-height: 100rpx; text-align: center; border-radius: 8rpx; font-size:35rpx; } @keyframes slidedown { from { transform: translateY(0); } to { transform: translateY(100%); } } .slidedown { animation: slidedown 0.5s linear ; } .slideup { animation: slideup 0.5s linear ; } @keyframes slideup { from { transform: translateY(100%); } to { transform: translateY(0); } }
再贴个搜索的
util.js
'use strict';/** * 格式化时间 * @param {Datetime} source 时间对象 * @param {String} format 格式 * @return {String} 格式化过后的时间 */function formatDate(source, format) { var o = { 'M+': source.getMonth() + 1, // 月份 'd+': source.getDate(), // 日 'H+': source.getHours(), // 小时 'm+': source.getMinutes(), // 分 's+': source.getSeconds(), // 秒 'q+': Math.floor((source.getMonth() + 3) / 3), // 季度 'f+': source.getMilliseconds() // 毫秒 }; if (/(y+)/.test(format)) { format = format.replace(RegExp.$1, (source.getFullYear() + '').substr(4 - RegExp.$1.length)); } for (var k in o) { if (new RegExp('(' + k + ')').test(format)) { format = format.replace(RegExp.$1, RegExp.$1.length === 1 ? o[k] : ('00' + o[k]).substr(('' + o[k]).length)); } } return format;}function formatTime(date) { var year = date.getFullYear() var month = date.getMonth() + 1 var day = date.getDate() var hour = date.getHours() var minute = date.getMinutes() var second = date.getSeconds() return [year, month, day].map(formatNumber).join('/') + ' ' + [hour, minute, second].map(formatNumber).join(':')}function mergeDeep(target, ...sources) { if (!sources.length) return target; const source = sources.shift(); if (isObject(target) && isObject(source)) { for (const key in source) { if (isObject(source[key])) { if (!target[key]) Object.assign(target, { [key]: {} }); mergeDeep(target[key], source[key]); } else { Object.assign(target, { [key]: source[key] }); } } } return mergeDeep(target, ...sources);}function isObject(item) { return (item && typeof item === 'object' && !Array.isArray(item));}function haveSomeMinutesTime(n) { if (n == null) { n = 0; } // 时间 var newDate = new Date() // var timeStamp = newDate.getTime(); //获取时间戳 var date = newDate.setMinutes(newDate.getMinutes() + n); newDate = new Date(date); var year = newDate.getFullYear(); var month = newDate.getMonth() + 1; var day = newDate.getDate(); var h = newDate.getHours(); var m = newDate.getMinutes(); var s = newDate.getSeconds(); if (month < 10) { month = '0' + month; }; if (day < 10) { day = '0' + day; }; if (h < 10) { h = '0' + h; }; if (m < 10) { m = '0' + m; }; if (s < 10) { s = '0' + s; }; var time = year +"-"+ month +"-"+ day; return time;}// 网络请求const request = function(url, method, data, msg, succ, fail, com) { // 小程序顶部显示Loading wx.showNavigationBarLoading(); if (msg != "") { wx.showLoading({ title: msg }) } wx.request({ url: 'https://***.cn'+url, data: data, header: { 'content-type': 'application/x-www-form-urlencoded' }, method: method, success: res => { if (succ) succ(res); }, fail: err => { wx.showToast({ title: '网络错误,请稍后再试···', icon:'none' }) if (fail) fail(err); }, complete: com => { wx.hideNavigationBarLoading(); if (msg != "") { wx.hideLoading(); } console.log(url + ' 返回的data:', com.data); } })}function formatNumber(n) { n = n.toString() return n[1] ? n : '0' + n}module.exports = { formatDate: formatDate, formatTime:formatTime, mergeDeep: mergeDeep, haveSomeMinutesTime: haveSomeMinutesTime, request: request, formatNumber:formatNumber,};
总结:修改下服务端就可以实现私聊群聊
转载地址:http://aatin.baihongyu.com/